#include <stdlib.h>
#include "dig_non_lock_queue.h"

typedef struct one_read_one_write_node
{
    volatile struct one_read_one_write_node *next_;
    void *value_;
}orow_node_t;

struct one_read_one_write_queue
{
    volatile unsigned long write_count_;
    volatile unsigned long read_count_;
    volatile orow_node_t *read_node_;
    volatile orow_node_t *write_node_;
    volatile orow_node_t *data_node_;
};

orow_node_t *
orow_node_create()
{
    orow_node_t *node = malloc(sizeof(orow_node_t));
    node->next_ = NULL;
    node->value_ = NULL;
    return node;
}

void
orow_node_delete(orow_node_t *node)
{
    free(node);
}

orow_queue_t *
orow_queue_create()
{
    orow_queue_t *queue = malloc(sizeof(orow_queue_t));
    queue->write_count_ = 0;
    queue->read_count_ = 0;
    queue->data_node_ = orow_node_create();
    queue->write_node_ = queue->data_node_;
    queue->read_node_ = queue->data_node_;
    return queue;
}


void
orow_queue_delete(orow_queue_t *queue)
{
    while (queue->data_node_ != queue->write_node_)
    {
            volatile orow_node_t* value_node = queue->data_node_;
            queue->data_node_ = value_node->next_;
            orow_node_delete(value_node);
    }
    free(queue);
}

void 
orow_queue_enqueue(orow_queue_t *queue, void *value)
{
    volatile orow_node_t* newnode = 0;
    if (queue->data_node_ == queue->read_node_)
    {
        newnode = orow_node_create();
    }
    else
    {
        newnode = queue->data_node_;
        queue->data_node_ = queue->data_node_->next_;
    }
    queue->write_node_->value_ = value;
    queue->write_node_->next_ = newnode;
    queue->write_node_ = newnode;
    ++queue->write_count_;
}

void *
orow_queue_dequeue(orow_queue_t *queue)
{
    if (queue->write_count_ > queue->read_count_)
    {
        void *value = queue->read_node_->value_;
        queue->read_node_ = queue->read_node_->next_;
        ++queue->read_count_;
        return value;
    }
    return NULL;
};


int
orow_queue_is_empty(const orow_queue_t *queue)
{
    return queue->write_count_ == queue->read_count_;
}
